var socketio = require('socket.io');
var io;
var guestNumber = 1;
var nickNames = {};
var nameUsed = [];
var currentRoom = {};

//  启动socket.IO服务器

exports.listen = function(server) {
	io = socketio.listen(server); // 启动socket IO服务器，允许它搭载在已有的HTTP服务器上
	io.set('log level', 1);
	io.sockets.on('connection', function(socket) {   // 定义每个用户连接的处理逻辑
		guestNumber = assignGuestName(socket, guestNumber, nickNames, namesUsed); // 在用户连接上来时赋予其一个访客名
		joinRoom(socket, 'Lobby');  // 在用户连接上来时把他放入聊天室Lobby里面

		handleMessageBroadcasting(socket, nickNames); // 处理用户的消息，更名，以及聊天室的创建和变更
		handleNameChangeAttempts(socket, nickNames, namesUsed);
		handleRoomJoining(socket);

		socket.on('rooms', function() {
			socket.emit('rooms', io.sockets.manager.rooms);
		});
		handleClientDisconnection(socket, nickNames, namesUsed);  // 定义用户断开连接后的清楚逻辑

	});
}

//  分配用户的昵称
/**
 * [assignGuestName 用来处理新用户的昵称，当用户第一次连接到聊天服务器上时， 用户会被放到一个叫做Lobby的聊天室中，并调用assignGuestName给他们分配一个昵称，以便于相互分开。程序分配的所有昵称基本上都是在Guest后面加上一个数字，有新用户连进来时这个数字就会往上增长。用户昵称存在变量nickNames中以便于引用，并且会跟一个内部socketID关联。昵称还会被添加到namesUsed中， 这个变量中保存的是已经被占用的昵称。]
 * @param  {[Object]} socket      [socket]
 * @param  {[Number]} guestNumber [用户的昵称]
 * @param  {[Object]} nickNames   [用来存放用户昵称的对象]
 * @param  {[Array]} namesUsed   [用来存放已经被占用的昵称]
 * @return {[Number]}             [返回自增1的guestNumber]
 */
function assignGuestName(socket, guestNumber, nickNames, namesUsed) {
	var name = 'Guest' + guestNumber;  //  生成新昵称
	nickNames[socket.id] = name;  //  把用户昵称跟客户端的连接ID关联上
	socket.emit('nameResult', { // 让用户知道他们的昵称
		success : true,
		name : name
	});
	nameUsed.push(name);  //  存放已经被占用的昵称
	return guestNumber + 1; // 增加用来生成昵称的计数器
}

// 进入聊天室逻辑

/**
 * [joinRoom 主要的功能是将用户加入到Socket.IO房间，使用socket对象上的join方法即可。然后程序会把相关的细节问题向这个用户以及同一房间中的其他用户发送.程序会让用户知道有哪些用户在这个房间里，还会让其他用户知道这个用户进来了.]
 * @param  {[Object]} socket [socket对象]
 * @param  {[]} room   [description]
 * @return {[undefined]}        [description]
 */
function joinRoom(socket, room) {
	socket.join(room);    //  让用户进入房间
	currentRoom[socket.id] = room; // 记录用户的当前房间
	socket.emit('joinResult', {
		room : room
	});  // 让用户知道他们进入了新的房间
	socket.broadcast.to(room).emit('message', {   //  让房间里的其他用户知道有新用户进入了房间
		text : nickNames[socket.id] + ' has joined ' + room + '.'
	});
	var usersInRoom = io.sockets.clients(room);  
	if (usersInRoom.length > 1) {  //  如果不止一个用户在这个房间里，汇总一下都是谁
		var usersInRoomSummary = 'Users currently in ' + room + ': ';
		for (var index in usersInRoom) {
			var userSocketId = usersInRoom[index].id;
			if (userSocketId != socket.id) {
				if (index > 0) {
					usersInRoomSummary += ', ';
				}
				usersInRoomSummary += nickNames[userSocketId];
			}
		}
		usersInRoomSummary += '.';
		socket.emit('message', {  
			text : usersInRoomSummary  //   将房间里其他用户的汇总发送给这个用户
		});
	}
}

//  处理昵称变更请求
/**
 * [handleNameChangeAttempts 处理用户发起的更名请求, 更名需要用户的浏览器发送一个Socket.io的请求，并接受表示成功或者失败的响应,用户不能将昵称改成以Guest开头，或改成其他的已经被占用的昵称]
 * @param  {[Object]} socket    [socket对象]
 * @param  {[Object]} nickNames [存储用户昵称的对象，key为socketId,value为name]
 * @param  {[Array]} namesUsed [存储已经被占用的name]
 * @return {[json]}           [返回表示修改成功或失败的json字符串]
 */
function handleNameChangeAttempts(socket, nickNames, namesUsed) {
	socket.on('nameAttempt', function(name) { // 添加nameAttempt事件的监听器
		if (name.indexOf('Guest') == 0) { // 昵称不能以Guest开头
			socket.emit('nameResult', {
				success : false,
				message : 'Names cannot begin with "Guest".'
			});
		} else {
			if (namesUsed.indexOf(name) == -1) { // 如果昵称没有被占用就用这个昵称注册
				var previousName = nickNames[socket.id]; // 拿到默认分配的昵称
				var previousNameIndex = namesUsed.indexOf(previousName);   // 默认昵称在已占用昵称数组中的索引
				nickNames[socket.id] = name; // 将更换的昵称更新到nickNames对象中
				delete namesUsed[previousNameIndex];  //  删掉之前用的昵称，让其他用户可以使用
				socket.emit('nameResult', {
					success : true,
					name : name
				});
				socket.broadcast.to(currentRoom[socket.id]).emit('message', {
					text : previousName + ' is now known as ' + name + '.'
				});
			} else {
				socket.emit('nameResult', {  //  如果昵称已经被占用了,给客户端发送错误的消息
					success : false,
					message : 'That name is already in use.'
				});
			}
		}
	});
}

// 发送聊天消息
/**
 * [handleMessageBroadcasting 处理流程，用户发射一个事件，表明 消息是从哪个房间发出来的，以及消息的内容是什么，然后服务器将这个消息转发给同一个房间的所有用户]
 * @param  {[Object]} socket [socket对象]
 * @return {[type]}        [description]
 */
function handleMessageBroadcasting(socket) {
	socket.on('message', function(message) {
		socket.broadcast.to(message.room).emit('message', {
			text : nickNames[socket.id] + ' : ' + message.text
		});
	})
}

// 创建房间

function handleRoomJoining(socket) {
	socket.on('join', function(room) {
		socket.leave(currentRoom[socket.id]);
		joinRoom(socket, room.newRoom);
	});
}

//  用户断开连接

function handleClientDisconnection(socket) {
	socket.on('disconnect', function() {
		var nameIndex = namesUsed.indexOf(nickNames[socket.id]);
		delete namesUsed[nameIndex];
		delete nickNames[socket.id];
	});
}